package com.lcc.lynx.common.utils;


import com.lcc.lynx.common.exception.e.ReflectException;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.type.TypeFactory;

import java.io.IOException;

import java.lang.reflect.*;
import java.util.*;

/**
 * 反射工具类
 * auth lcc
 */
public class ReflectUtil {

    private static final Map<Class<?>, List<Field>> fieldsCache = new HashMap<>();

    /**
     * 获取class对象
     *
     * @param name
     * @return
     */
    public static Class<?> getClass(String name) {
        StrUtil.isNotBlank("类名不能为空", name);
        try {
            return Class.forName(name);
        } catch (ClassNotFoundException e) {
            throw new ReflectException(e.getMessage());
        }
    }

    /**
     * 获取class中全部字段包括父类，并设置Accessible为true
     *
     * @param clazz
     * @return
     */
    public static List<Field> getFields(Class<?> clazz) {
        StrUtil.isNotBlank("获取字段的class不能为null", clazz);
        if (fieldsCache.containsKey(clazz)) {
            return fieldsCache.get(clazz);
        }
        List<Field> fields0 = getFields0(clazz);
        fieldsCache.put(clazz, fields0);
        return fields0;
    }

    private static List<Field> getFields0(Class<?> clazz) {
        List<Field> fields = new ArrayList<>();
        if (clazz == Object.class) {
            return fields;
        }
        fields.addAll(getFields(clazz.getSuperclass()));
        fields.forEach(item -> item.setAccessible(true));
        Collections.addAll(fields, clazz.getDeclaredFields());
        return fields;
    }

    /**
     * 获取对象的某个字段
     *
     * @param clazz
     * @param name
     * @return
     */
    public static Field getField(Class<?> clazz, String name) {
        StrUtil.isNotBlank("字段名称不能为空", name);
        for (Field field : getFields(clazz)) {
            if (field.getName().equals(name)) {
                return field;
            }
        }
        throw new ReflectException("未找到字段：" + name);
    }

    /**
     * 获取对象的某个字段
     *
     * @param clazz
     * @param name
     * @return
     */
    public static Field getFieldNoException(Class<?> clazz, String name) {
        StrUtil.isNotBlank("字段名称不能为空", name);
        for (Field field : getFields(clazz)) {
            if (field.getName().equals(name)) {
                return field;
            }
        }
        return null;
    }

    /**
     * 获取对象的某个字段
     *
     * @param clazz
     * @param name
     * @return
     */
    public static Field getFieldLike(Class<?> clazz, String name, String column) {
        StrUtil.isNotBlank("字段名称不能为空", name);
        for (Field field : getFields(clazz)) {
            if (field.getName().equalsIgnoreCase(name) || field.getName().equalsIgnoreCase(column)) {
                return field;
            }
        }
        return null;
    }

    /**
     * 通过get方法获取对象属性值
     *
     * @param obj
     * @param name
     * @return
     */
    public static Object getObjValue(Object obj, String name) {
        StrUtil.isNotBlank("获取字段的对象不能为null", obj);
        StrUtil.isNotBlank("字段名称不能为空", name);
        String methodName = "get" + name.substring(0, 1).toUpperCase() + name.substring(1);
        return exeInvoke(obj, methodName, null);
    }

    /**
     * 通过set方法设置对象的属性值
     *
     * @param obj
     * @param name
     * @param val
     */
    public static void setObjValue(Object obj, String name, Object val) {
        StrUtil.isNotBlank("字段名称不能为空", name);
        setObjValue(obj, getField(obj.getClass(), name), val);
    }

    /**
     * 通过set方法设置对象的属性值
     *
     * @param obj
     * @param field
     * @param val
     */
    public static void setObjValue(Object obj, Field field, Object val) {
        StrUtil.isNotBlank("设置字段的对象不能为null", obj);
        StrUtil.isNotBlank("字段不能为空", field);
        String methodName = "set" + field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1);
        exeInvoke(obj, methodName, field.getType(), convertValType(val, field.getType()));
    }

    /**
     * 通过field暴力获取对象值
     *
     * @param obj
     * @param field
     * @return
     */
    public static Object getFieldValue(Object obj, Field field) {
        StrUtil.isNotBlank("获取对象不能为null", obj);
        StrUtil.isNotBlank("获取字段不能为null", field);
        field.setAccessible(true);
        try {
            return field.get(obj);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
            throw new ReflectException("获取对象字段值异常：" + field.getName());
        }
    }

    /**
     * 通过field暴力设置对象值
     *
     * @param obj
     * @param field
     * @param val
     */
    public static void setFieldValue(Object obj, Field field, Object val) {
        StrUtil.isNotBlank("设置对象不能为null", obj);
        StrUtil.isNotBlank("设置字段不能为null", field);
        field.setAccessible(true);
        try {
            Class<?> type = field.getType();
            field.set(obj, convertValType(val, type));
        } catch (IllegalArgumentException | IllegalAccessException e) {
            throw new ReflectException("给对象字段赋值异常(" + e.getMessage() + ")，无法将值(" + val + ")赋值给类型(" + val.getClass() + ")");
        }
    }

    public static Object convertValType(Object val, Class<?> type){
        if (val != null && val.getClass() == type) {
            return val;
        }
        if (val != null && !type.isAssignableFrom(val.getClass())) {
            try {
                val = type.getConstructor(String.class).newInstance(val.toString());
            } catch (Exception e) {
                throw new ReflectException("无法将值(" + val + ")转成类型(" + type.toString().substring(type.toString().lastIndexOf(".") + 1) + ")");
            }
        }
        return val;
    }

    /**
     * 执行对象的某个方法
     *
     * @param obj
     * @param methodName
     * @param paramType
     * @param params
     * @return
     */
    public static Object exeInvoke(Object obj, String methodName, Class<?> paramType, Object... params) {
        StrUtil.isNotBlank("执行对象不能为null", obj);
        StrUtil.isNotBlank("方法名称不能为空", methodName);
        Class<?> clazz = obj.getClass();
        Method method;
        try {
            if (paramType == null) {
                method = clazz.getMethod(methodName);
            } else {
                method = clazz.getMethod(methodName, paramType);
            }
        } catch (NoSuchMethodException e) {
            throw new ReflectException("无法获取方法：" + methodName);
        }
        try {
            return method.invoke(obj, params);
        } catch (IllegalAccessException | InvocationTargetException e) {
            throw new ReflectException(e.getMessage());
        }
    }

    public static Object getValue(Object obj, String fieldName) {
        if (obj == null) {
            throw new ReflectException("对象不能为null");
        }
        if (fieldName == null || fieldName.isEmpty()) {
            throw new ReflectException("属性名不能为null或空");
        }

        try {
            return obj.getClass().getMethod("get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1))
                    .invoke(obj);
        } catch (NoSuchMethodException e) {
            throw new ReflectException("未获取到get方法：" + fieldName);
        } catch (InvocationTargetException e) {
            throw new ReflectException("调用get方法出错：" + fieldName);
        } catch (IllegalAccessException e) {
            throw new ReflectException("非法访问get方法：" + fieldName);
        }
    }

    /**
     * 获取json别名
     *
     * @param c         class对象
     * @param fieldName
     * @return
     * @author lcc
     * @date 2024/7/29 18:57
     */
    public static String getJsonPropertyName(Class c, String fieldName) {
        if (c == null) {
            throw new ReflectException("对象class不能为null");
        }
        if (fieldName == null || fieldName.isEmpty()) {
            throw new ReflectException("属性名不能为null或空");
        }
        // 获取字段注解JsonProperty的value值并返回
        JsonProperty annotation = null;
        try {
            annotation = getFieldByFieldName(c, fieldName).getAnnotation(JsonProperty.class);
        } catch (NoSuchFieldException e) {
            throw new ReflectException("未获取到字段：" + fieldName);
        }

        if (annotation != null) {
            return annotation.value();
        }
        return fieldName;
    }

    /**
     * 获取obj对象fieldName的Field
     *
     * @param c
     * @param fieldName
     * @return
     */
    private static Field getFieldByFieldName(Class c, String fieldName) throws NoSuchFieldException {
        for (Class<?> superClass = c; superClass != Object.class; superClass = superClass.getSuperclass()) {
            try {
                return superClass.getDeclaredField(fieldName);
            } catch (NoSuchFieldException e) {
            }
        }
        throw new NoSuchFieldException();
    }

    /**
     * 获取clazz第一个泛型类型实例
     * 父类为抽象类
     *
     * @param clazz 带有泛型的类
     * @param <T>
     * @return
     * @author lcc
     * @date 2024/10/25 10:04
     */
    public static <T> T invokeGeneric(Class clazz, int index) {
        try {
            Type type = ((ParameterizedType) clazz.getGenericSuperclass()).getActualTypeArguments()[index];
            return (T) ((Class) type).newInstance();
        } catch (Exception e) {
            throw new ReflectException("实例化泛型对象出错：" + e.getMessage(), e);
        }
    }

    /**
     * 获取实现接口第一个泛型类型实例
     *
     * @param paramType 带有泛型的接口
     * @param <T>
     * @return
     * @author lcc
     * @date 2024/10/25 10:04
     */
    public static <T> T invokeGenericIntf(ParameterizedType paramType, int index) {
        try {
            // 获取泛型参数的实际类型
            Class<T> type = (Class<T>) paramType.getActualTypeArguments()[index];
            return (T) ((Class) type).newInstance();
        } catch (Exception e) {
            throw new ReflectException("实例化泛型对象出错：" + e.getMessage(), e);
        }
    }


    /**
     * 获取clazz第一个泛型类型实例并通过json反序列化
     *
     * @param json
     * @param clazz 带有泛型的类
     * @param <T>
     * @return
     * @throws IOException
     * @author lcc
     * @date 2024/10/25 10:13
     */
    public static <T> T invokeGenericJson(String json, Class clazz, int index) {
        try {
            Type type = ((ParameterizedType) clazz.getGenericSuperclass()).getActualTypeArguments()[index];
            JavaType javaType = TypeFactory.defaultInstance().constructType(type);
            return JsonUtil.parseObject(json, javaType);
        } catch (Exception e) {
            throw new ReflectException("反序列化泛型对象出错：" + e.getMessage(), e);
        }
    }

    /**
     * 实例化对象或父类对象或父类接口的第几个泛型参数
     *
     * @param objClass        当前对象
     * @param parentIntfClass 含有泛型的实现的接口
     * @param i               第几个泛型参数
     * @param <T>
     * @return
     * @author lcc
     * @date 2025/1/22 14:55
     */
    public static <T> T newInstance(Class<?> objClass, Class<?> parentIntfClass, int i) {
        if (parentIntfClass == null) {
            return invokeGeneric(objClass, i);
        }
        for (Type genericInterface : objClass.getGenericInterfaces()) {
            if (genericInterface instanceof ParameterizedType) {
                ParameterizedType type = (ParameterizedType) genericInterface;
                if (type.getRawType() == parentIntfClass) {
                    return invokeGenericIntf(type, i);
                }
            }

        }
        throw new ReflectException("无法实例化泛型，未找到接口：" + parentIntfClass.getName());
    }

    public static <T> T newInstance(Class<?> objClass) {
        try {
            return (T) objClass.getConstructor().newInstance();
        } catch (Exception e) {
            throw new ReflectException("实例化对象出错: " + e.getMessage());
        }
    }


    public static Object getStaticValue(Class<?> clazz, String fieldName) {
        Field field = getField(clazz, fieldName);
        field.setAccessible(true);
        try {
            return field.get(null);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
            throw new ReflectException("获取对象静态字段值(" + fieldName + ")异常：" + field.getName());
        }

    }

}
